/**
 * \file PluginObject_Win32.h
 * \brief Plugin declaration class for Windows platforms
 * \author Edouard ROGE
 * \date 16 March 2013
 */
#ifndef _PLUGINOBJECT_WIN32_
#define _PLUGINOBJECT_WIN32_

#include <Windows.h>
#include <string>
#include "Core/Log/LogManager.h"
#include "Plugin.h"

namespace Core
{
	namespace Plugin
	{
		/**
		 * \class PluginObject
		 * \brief Base class for every plug-in
		 */
		template<typename T>
		class PluginObject : public Plugin
		{
		public:

			/**
			 * \fn PluginObject()
			 * \brief Default constructor
			 */
			PluginObject() :Plugin()
			{
			}

			/**
			 * \fn virtual ~PluginObject()
			 * \brief Destructor
			 */
			virtual ~PluginObject()
			{
			}

			/**
			 * \fn error Load(const String & _strPluginName)
			 * \param _strPluginName name of the plug-in to load
			 * \return an error if occurs
			 * \brief Load a Plugin
			 */
			virtual error Load(const std::string & _strPluginName)
			{
				m_hLibrary = ::LoadLibrary(_strPluginName.c_str());
				if (!m_hLibrary)
				{
					LOG_ERROR("Couldn't find %s plugin", _strPluginName.c_str());
					return errFailed;
				}

				LOADINGFUNCTION pLoadingFunc = (LOADINGFUNCTION)::GetProcAddress(m_hLibrary, "CreatePlugin");
				if (!pLoadingFunc)
				{
					LOG_ERROR("Couldn't find loading function in %s plugin", _strPluginName.c_str());
					return errFailed;
				}

				m_pInterface = pLoadingFunc();

				if (!m_pInterface)
				{
					Unload();
					LOG_ERROR("Couldn't findinterface in  %s plugin", _strPluginName.c_str());
					return errFailed;
				}

				return errOK;
			}

			/**
			 * \fn error Unload()
			 * \return an error if occurs
			 * \brief Unload a Plugin
			 */
			virtual error Unload()
			{

				UNLOADINGFUNCTION pUnLoadingFunc = (UNLOADINGFUNCTION)::GetProcAddress(m_hLibrary, "ReleasePlugin");
				if (!pUnLoadingFunc)
				{
					LOG_ERROR("Couldn't find unloading function in %s plugin", m_pInterface->GetName().c_str());
					return errFailed;
				}

				pUnLoadingFunc((T*)m_pInterface);

				m_pInterface = NULL;

				::FreeLibrary(m_hLibrary);

				return errOK;
			}

		private:

			/** Handle to the loaded plug-in */
			HINSTANCE m_hLibrary;

			typedef T* (*LOADINGFUNCTION)();

			typedef void(*UNLOADINGFUNCTION)(T*);
		};
	}
}

#endif // _PLUGINOBJECT_WIN32_

